﻿using Gma.QrCodeNet.Encoding.Windows.Render;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace _2dTo3D
{

    public class QrEncodingProvider
    {
        public enum CorrectionLevel
        {
            Low,
            Medium,
            High,
            ExtraHigh
        }

        Gma.QrCodeNet.Encoding.QrEncoder Encoder;
        public QrEncodingProvider(CorrectionLevel correction)
        {
            Gma.QrCodeNet.Encoding.ErrorCorrectionLevel errorCorrectionLevel;
            switch (correction)
            {
                case CorrectionLevel.Low:
                    errorCorrectionLevel = Gma.QrCodeNet.Encoding.ErrorCorrectionLevel.L;
                    break;
                case CorrectionLevel.Medium:
                    errorCorrectionLevel = Gma.QrCodeNet.Encoding.ErrorCorrectionLevel.M;
                    break;
                case CorrectionLevel.High:
                    errorCorrectionLevel = Gma.QrCodeNet.Encoding.ErrorCorrectionLevel.Q;
                    break;
                case CorrectionLevel.ExtraHigh:
                    errorCorrectionLevel = Gma.QrCodeNet.Encoding.ErrorCorrectionLevel.H;
                    break;
                default:
                    throw new InvalidOperationException("Unsuported Enum Value");
            }
            Encoder = new Gma.QrCodeNet.Encoding.QrEncoder(errorCorrectionLevel);
        }

        public void Encode(System.Uri url, Stream stream, Int32 size, Brush foreground, Brush background)
        {
            Encode(url.OriginalString, stream, size, foreground, background);
        }

        public void Encode(String text, Stream stream, Int32 size, Brush foreground, Brush background)
        {
            Gma.QrCodeNet.Encoding.QrCode qr = Encoder.Encode(text);
            //Gma.QrCodeNet.Encoding..Controls.Renderer renderer = new Gma.QrCodeNet.Encoding.Windows.Render.Renderer(size, foreground, background);
            //renderer.WriteToStream(qr.Matrix, stream, System.Drawing.Imaging.ImageFormat.Bmp);

            GraphicsRenderer gRender = new GraphicsRenderer(new FixedModuleSize(size, QuietZoneModules.Two), foreground, background);
            gRender.WriteToStream(qr.Matrix, System.Drawing.Imaging.ImageFormat.Bmp, stream);
        }
        public void Dispose()
        {
            Encoder = null;
        }
    }
    public partial class _3DQRCodeGenerator : System.Web.UI.Page
    {
        private QrEncodingProvider QrProvider = new QrEncodingProvider(QrEncodingProvider.CorrectionLevel.ExtraHigh);
        protected void Page_Load(object sender, EventArgs e)
        {
            var qrValue = txtValue.Text;
            var depth = Int32.Parse(ddlDepth.SelectedValue);
            var pixelMultiplier = Int32.Parse(ddlPixelMultiplier.SelectedValue);
            Boolean invert = ddlLightOrDark.SelectedValue == "Light";
            var baseDepth = 1;
            var padding = 4 * pixelMultiplier;
            
            if (!String.IsNullOrWhiteSpace(qrValue))
            {
                using (var qrStream = new MemoryStream())
                {
                    QrProvider.Encode(qrValue, qrStream, 1, Brushes.Black, Brushes.White);

                    using (Bitmap img = new Bitmap(qrStream))
                    {

                        //var saveAs = "c:/test/" + DateTime.Now.Ticks + "_" + fulImage.FileName.Replace(fileExt, ".bmp");
                        if (img.Height > 130)
                            throw new Exception("Height limit 100px");

                        if (img.Width > 130)
                            throw new Exception("Width limit 100px");

                        Response.Clear();
                        Response.ContentType = "application/sla";
                        Response.AddHeader("content-disposition", String.Format("attachment;filename={0}-D{1}-M{2}-{3}.scad", DateTime.Now.Ticks, depth, pixelMultiplier, ddlLightOrDark.SelectedValue));
	                    if (invert)
	                    {

		                    Response.Write("\ncolor(\"White\") {");
	                    }
	                    else
	                    {
		                    Response.Write("\ncolor(\"Grey\") {");
	                    }
	                    Response.Write("\n\tunion() {");	

                        var yMax = img.Height;
                        if (yMax % 2 != 0)
                            yMax = img.Height + 1;
                        yMax = yMax * pixelMultiplier;

                        var yMaxCentered = (yMax / 2);
                        var yMinCentered = yMaxCentered - yMax;

                        var xMax = img.Width;
                        if (xMax % 2 != 0)
                            xMax = img.Width + 1;
                        xMax = xMax * pixelMultiplier;

                        var xMaxCentered = (xMax / 2);
                        var xMinCentered = xMaxCentered - xMax;

                        var  y = yMinCentered;
                        var yCoord = img.Height;
                        while (y <  yMaxCentered)
                        {
                            y = y + pixelMultiplier;
                            var x = xMinCentered;
                            var xCoord = 0;
                            while (x < xMaxCentered)
                            {
                                x = x + pixelMultiplier;
								if (IsDarkPixel(xCoord, yCoord, img) ^ invert)
                                {

									Response.Write(String.Format("\n\t\ttranslate ([{0},{1},{2}]){{", x + pixelMultiplier, y + pixelMultiplier, baseDepth * pixelMultiplier));
									Response.Write(String.Format("\n\t\t\tcube ([{0},{1},{2}]); \n", pixelMultiplier, pixelMultiplier, depth * pixelMultiplier));
									Response.Write(String.Format("\n\t\t }}"));
                                }
                                xCoord++;
                            }
                            Response.Flush();
                            yCoord--;
                        }
                        var bottomMax = xMax;
                        var bottomX = xMinCentered;
                        if (img.Width % 2 != 0)
                        {
                            bottomMax = bottomMax - pixelMultiplier;
                            bottomX = bottomX + pixelMultiplier;
						}
						if (invert)
						{
							//Response.Write(String.Format("\n\ttranslate ([{0},{1},{2}]){{", xMinCentered - pixelMultiplier, yMinCentered - pixelMultiplier, 0));
							//Response.Write(String.Format("\n\t\tcube ([{0},{1},{2}]); \n", pixelMultiplier, (yMax + 1) * pixelMultiplier, baseDepth * pixelMultiplier));
							//Response.Write("\n}");

							//Response.Write(String.Format("\n\ttranslate ([{0},{1},{2}]){{", xMinCentered - pixelMultiplier, yMinCentered - pixelMultiplier, 0));
							//Response.Write(String.Format("\n\t\tcube ([{0},{1},{2}]); \n", (xMax + 1) * pixelMultiplier, pixelMultiplier, baseDepth * pixelMultiplier));
							//Response.Write("\n}");
						}
						else
						{
							Response.Write(String.Format("\n\t\ttranslate ([{0},{1},{2}]){{", xMinCentered + (pixelMultiplier * 2), yMinCentered + (pixelMultiplier * 2), 0));
							Response.Write(String.Format("\n\t\t\tcube ([{0},{1},{2}]); \n", xMax, yMax, baseDepth * pixelMultiplier));
							Response.Write("\t\n}");
						}
						Response.Write("\t\n}");
						Response.Write("\n}");

                        Response.End();
                    }
                }
            }
        }
     
        protected bool IsDarkPixel(Int32 xCoord, Int32 yCoord, Bitmap img)
        {
            if (xCoord < 0 || yCoord <= 0 || xCoord >= img.Width || yCoord > img.Height)
            {
                return false;
            }

            var color = img.GetPixel(xCoord, yCoord - 1);
            Boolean darkPixel = ((color.R + color.G + color.B) < 300);
            if (color.A > 100 && darkPixel)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}